<template>
  <div class="user-profile-page">
    <!-- ========== 可选：动态背景特效开关 ========== -->
    <div class="position-absolute top-0 end-0 p-3">
      <div class="form-check form-switch">
        <input
          class="form-check-input"
          type="checkbox"
          id="backgroundEffectSwitch"
          v-model="enableDynamicBg"
        />
        <label class="form-check-label text-white" for="backgroundEffectSwitch">
          动态背景
        </label>
      </div>
    </div>

    <!-- 背景层（渐变） -->
    <div class="immersive-background"></div>

    <!-- 半透明遮罩（柔和白光） -->
    <div class="immersive-overlay"></div>

    <!-- 可选：动态悬浮特效 -->
    <div v-if="enableDynamicBg" class="floating-shapes-container">
      <div
        v-for="(shape, idx) in floatingShapes"
        :key="idx"
        class="floating-shape"
      ></div>
    </div>

    <div class="container py-4 user-profile-container position-relative">
      <!-- ========== 顶部：个人信息与签到区 ========== -->
      <div class="row g-4 mb-4">
        <!-- 左侧：用户信息卡片 -->
        <div class="col-12 col-md-4">
          <div class="card user-info-card shadow-sm">
            <div class="card-body d-flex flex-column align-items-center p-4">
              <!-- 头像区域 -->
              <div class="avatar mb-3 position-relative">
                <img
                  v-if="user?.avatar"
                  :src="user.avatar"
                  alt="用户头像"
                  class="rounded-circle img-shadow"
                  style="width: 120px; height: 120px; object-fit: cover;"
                />
                <div
                  v-else
                  class="rounded-circle bg-primary d-flex align-items-center justify-content-center"
                  style="width: 120px; height: 120px;"
                >
                  <span class="text-white fs-4">
                    {{ user?.username?.charAt(0).toUpperCase() || 'U' }}
                  </span>
                </div>
                <!-- 小装饰物动画 -->
                <div class="float-decoration"></div>
              </div>

              <!-- 用户基本信息 -->
              <h5 class="card-title mb-1 text-dark">
                {{ user?.username }}
              </h5>
              <p class="text-muted mb-2 small">
                {{ user?.email }}
              </p>

              <!-- 编辑信息按钮 -->
              <button
                class="btn btn-outline-primary btn-sm"
                @click="toggleEditUserModal"
              >
                编辑个人信息
              </button>
            </div>
          </div>
        </div>

        <!-- 右侧：签到 & 今日日期 & 背诵提醒 -->
        <div class="col-12 col-md-8">
          <div class="card user-info-card shadow-sm">
            <div class="card-body p-4">
              <!-- 今日日期 & 签到打卡 -->
              <div
                class="d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between mb-3"
              >
                <div class="mb-3 mb-sm-0">
                  <h5 class="text-dark fw-bold">今天是：{{ currentDateStr }}</h5>
                  <p class="text-muted mb-1">
                    当前已连续登录：
                    <strong>{{ user?.consecutive_login_days }}</strong> 天
                  </p>
                  <p class="text-muted mb-1">
                    历史最高连续打卡：
                    <strong>{{ user?.max_streak || 0 }}</strong> 天
                  </p>
                  <p class="text-muted mb-1">
                    已累计打卡：
                    <strong>{{ user?.daily_check_in }}</strong> 次
                  </p>
                  <p class="text-muted mb-1">
                    累计掌握词汇：
                    <!-- 使用我们从后端统计而来的 vocabularyCount -->
                    <strong>{{ vocabularyCount }}</strong> 个
                  </p>
                  <p class="text-muted">
                    昨日背诵单词：
                    <!-- 使用我们从后端统计而来的 yesterdayWordCount -->
                    <strong>{{ yesterdayWordCount }}</strong> 个
                  </p>
                </div>
                <div>
                  <button
                    class="btn btn-success px-3"
                    :disabled="checkInLoading"
                    @click="onCheckIn"
                  >
                    <span v-if="!checkInLoading">今日打卡</span>
                    <span v-else>打卡中...</span>
                  </button>
                </div>
              </div>

              <hr />

              <!-- 是否开启背诵提醒 -->
              <div class="d-flex align-items-center justify-content-between">
                <div class="form-check form-switch">
                  <input
                    class="form-check-input"
                    type="checkbox"
                    id="reminderSwitch"
                    v-model="isRecitationReminderEnabled"
                  />
                  <label class="form-check-label ms-2" for="reminderSwitch">
                    开启背诵提醒
                  </label>
                </div>
                <small class="text-muted">
                  （前端本地控制，若需与后端同步可自行扩展）
                </small>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- ========== 下方：折线图 / 柱状图 / 绿点阵图 ========== -->
      <div class="row g-4">
        <!-- 折线图：最近 7 天背诵统计 -->
        <div class="col-12 col-md-6">
          <div class="card user-info-card shadow-sm h-100">
            <div class="card-body p-4">
              <h5 class="mb-3 fw-bold text-dark">
                最近 7 天背诵统计
              </h5>
              <apexchart
                v-if="chartOptions7Days && series7Days"
                type="area"
                height="280"
                :options="chartOptions7Days"
                :series="series7Days"
              ></apexchart>
              <div v-else class="text-center text-muted">暂无数据</div>
            </div>
          </div>
        </div>

        <!-- 柱状图：最近 5 个月背诵统计 -->
        <div class="col-12 col-md-6">
          <div class="card user-info-card shadow-sm h-100">
            <div class="card-body p-4">
              <h5 class="mb-3 fw-bold text-dark">
                最近 5 个月背诵统计
              </h5>
              <apexchart
                v-if="chartOptions5Months && series5Months"
                type="bar"
                height="280"
                :options="chartOptions5Months"
                :series="series5Months"
              ></apexchart>
              <div v-else class="text-center text-muted">暂无数据</div>
            </div>
          </div>
        </div>
      </div>

      <!-- 绿点阵图：过去 365 天 -->
      <div class="row mt-4">
        <div class="col-12">
          <div class="card user-info-card shadow-sm">
            <div class="card-body p-4">
              <h5 class="mb-3 fw-bold text-dark">
                背诵打卡热力图（过去 365 天）
              </h5>
              <apexchart
                v-if="heatmapOptions && heatmapSeries"
                type="heatmap"
                :options="heatmapOptions"
                :series="heatmapSeries"
                :width="1240"
                :height="200"
              />
              <p class="mt-2 small text-muted">
                颜色深浅代表当日背诵的单词数多或少；鼠标悬浮查看具体数值。
              </p>
            </div>
          </div>
        </div>
      </div>

    </div>

    <!-- 编辑用户信息 模态框 -->
    <div
      class="modal fade"
      id="editUserModal"
      tabindex="-1"
      aria-labelledby="editUserModalLabel"
      aria-hidden="true"
      ref="editUserModalRef"
    >
      <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content border-0">
          <div class="modal-header">
            <h5 class="modal-title" id="editUserModalLabel">编辑个人信息</h5>
            <button
              type="button"
              class="btn-close"
              data-bs-dismiss="modal"
              aria-label="Close"
            ></button>
          </div>
          <div class="modal-body">
            <div class="mb-3">
              <label class="form-label">用户名</label>
              <input
                type="text"
                class="form-control"
                v-model="editUsername"
              />
            </div>

            <div class="mb-3">
              <label class="form-label">头像</label>
              <input
                class="form-control"
                type="file"
                accept="image/*"
                @change="onAvatarSelected"
              />
            </div>
            <div
              v-if="previewAvatar"
              class="my-3 d-flex justify-content-center"
            >
              <img
                :src="previewAvatar"
                alt="新的头像预览"
                style="width: 80px; height: 80px; object-fit: cover; border-radius: 50%;"
              />
            </div>
          </div>
          <div class="modal-footer">
            <button
              class="btn btn-secondary"
              data-bs-dismiss="modal"
            >
              取消
            </button>
            <button
              class="btn btn-primary"
              :disabled="updateProfileLoading"
              @click="updateProfile"
            >
              <span v-if="!updateProfileLoading">保存修改</span>
              <span v-else>保存中...</span>
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
/* ----------------------------------
 *  使用说明：
 *  1. 需安装 apexcharts & vue3-apexcharts
 *  2. 在 store 里准备好:
 *     - fetchReciteStats       (从 recite 模块获取统计数据)
 *     - checkIn                (签到)
 *     - refreshUser            (刷新用户资料，如连续登录天数等)
 *  3. 后端接口应能返回 365 天或更久的用户每日背诵数据
 * ---------------------------------- */

import { ref, onMounted, computed, reactive, watch } from 'vue';
import { useStore } from 'vuex';
import { format, parseISO, subDays, subMonths } from 'date-fns';
import 'bootstrap/dist/js/bootstrap.bundle.min.js';

// 如果在 main.js 全局注册了 vue3-apexcharts，则此处直接用即可；否则需局部注册
import ApexCharts from 'vue3-apexcharts';
const apexchart = ApexCharts; // 局部注册示例

const store = useStore();

// 通过 Vuex 获取当前用户信息
const user = computed(() => store.getters.currentUser);

// 通过 Vuex 获取背诵统计的 computed
const vocabularyCount = computed(() => store.getters.vocabularyCount);      // 累计掌握
const yesterdayWordCount = computed(() => store.getters.yesterdayWordCount); // 昨日背诵

// 是否开启动态背景特效
const enableDynamicBg = ref(true);
// 悬浮形状
const floatingShapes = ref(Array.from({ length: 8 })); // 8个随意的装饰块

// 本组件使用的每日活动记录，用于图表展示
const dailyActivities = ref([]);

// 签到加载状态
const checkInLoading = ref(false);

// 是否开启背诵提醒（前端本地存储示例）
const isRecitationReminderEnabled = ref(false);

// 页面加载后
onMounted(async () => {
  // 1. 加载背诵统计，并将 daily_stats => dailyActivities
  await loadDailyActivities();

  // 2. 从本地获取背诵提醒开关
  const reminderStr = localStorage.getItem('isRecitationReminderEnabled');
  isRecitationReminderEnabled.value = reminderStr === 'true';

  // 动态背景开关
  const dynamicBgStr = localStorage.getItem('enableDynamicBg');
  if (dynamicBgStr !== null) {
    enableDynamicBg.value = dynamicBgStr === 'true';
  }
});

// 监听保存到 localStorage
watch(
  () => isRecitationReminderEnabled.value,
  (newVal) => {
    localStorage.setItem('isRecitationReminderEnabled', newVal ? 'true' : 'false');
  }
);
watch(
  () => enableDynamicBg.value,
  (newVal) => {
    localStorage.setItem('enableDynamicBg', newVal ? 'true' : 'false');
  }
);

/**
 * 加载背诵统计，并映射 daily_stats => dailyActivities
 */
async function loadDailyActivities() {
  try {
    const stats = await store.dispatch('fetchReciteStats');
    // stats 形如:
    // {
    //   vocabulary_count: 200,
    //   yesterday_word_count: 10,
    //   daily_stats: [
    //     { date: '2025-01-01', count: 7 },
    //     ...
    //   ]
    // }
    if (stats && stats.daily_stats) {
      dailyActivities.value = stats.daily_stats.map((item) => ({
        date: item.date,
        words_learned: item.count,
      }));
    }
  } catch (err) {
    console.error('获取背诵统计失败', err);
  }
}

// 签到打卡
async function onCheckIn() {
  try {
    checkInLoading.value = true;
    const res = await store.dispatch('checkIn');
    // 签到成功后刷新用户信息
    await store.dispatch('refreshUser');
    // 再次拉取统计信息，刷新图表
    await loadDailyActivities();
    alert(res.detail || '签到成功');
  } catch (err) {
    console.error(err);
    alert(err.detail || '签到失败');
  } finally {
    checkInLoading.value = false;
  }
}

// 当前日期
const currentDateStr = ref(format(new Date(), 'yyyy-MM-dd'));

/* ========== 折线图：最近7天统计 ========== */
const last7DaysData = computed(() => {
  const today = new Date();
  const sevenDaysAgo = subDays(today, 6);
  const map = {};

  dailyActivities.value.forEach((item) => {
    const d = parseISO(item.date);
    if (d >= sevenDaysAgo && d <= today) {
      map[item.date] = (map[item.date] || 0) + item.words_learned;
    }
  });

  const result = [];
  for (let i = 0; i < 7; i++) {
    const dStr = format(subDays(today, 6 - i), 'yyyy-MM-dd');
    result.push({
      date: dStr,
      words_learned: map[dStr] || 0,
    });
  }
  return result;
});

const chartOptions7Days = reactive({
  chart: {
    type: 'area',
    toolbar: { show: false },
    background: 'transparent',
    fontFamily: 'inherit',
    animations: {
      enabled: true,
      easing: 'easeinout',
      speed: 1000,
      dynamicAnimation: {
        speed: 600,
      },
    },
  },
  xaxis: {
    type: 'category',
    categories: last7DaysData.value.map((x) => x.date.slice(5)),
    labels: {
      style: {
        colors: '#333',
        fontSize: '12px',
      },
      rotate: -45,
    },
  },
  yaxis: {
    min: 0,
    labels: {
      style: {
        colors: '#333',
      },
      formatter: (val) => Math.floor(val),
    },
  },
  colors: ['#34c759'], // 苹果绿
  stroke: {
    curve: 'smooth',
    width: 2,
  },
  fill: {
    type: 'gradient',
    gradient: {
      shade: 'light',
      type: 'vertical',
      shadeIntensity: 0.25,
      gradientToColors: ['#78ef9c'],
      inverseColors: false,
      opacityFrom: 0.6,
      opacityTo: 0.25,
      stops: [0, 100],
    },
  },
  dataLabels: {
    enabled: false,
  },
  tooltip: {
    theme: 'light',
    y: {
      formatter: (val) => `${val} 个单词`,
    },
  },
  grid: {
    borderColor: '#ddd',
  },
});

const series7Days = computed(() => [
  {
    name: '背诵单词数',
    data: last7DaysData.value.map((x) => x.words_learned),
  },
]);

/* ========== 柱状图：最近5个月统计 ========== */
const last5MonthsData = computed(() => {
  const months = [];
  const today = new Date();
  // 取当前月以及之前4个月，共5个月
  for (let i = 4; i > 0; i--) {
    months.push(subMonths(today, i));
  }
  months.push(today);

  const map = {};
  dailyActivities.value.forEach((item) => {
    const d = parseISO(item.date);
    const key = format(d, 'yyyy-MM');
    map[key] = (map[key] || 0) + item.words_learned;
  });

  return months.map((m) => {
    const key = format(m, 'yyyy-MM');
    return {
      monthKey: key,
      totalWords: map[key] || 0,
    };
  });
});

const chartOptions5Months = reactive({
  chart: {
    type: 'bar',
    toolbar: { show: false },
    background: 'transparent',
    fontFamily: 'inherit',
    animations: {
      enabled: true,
      easing: 'easeinout',
      speed: 1000,
    },
  },
  xaxis: {
    type: 'category',
    categories: last5MonthsData.value.map((x) => x.monthKey),
    labels: {
      style: {
        colors: '#333',
      },
    },
  },
  yaxis: {
    labels: {
      style: {
        colors: '#333',
      },
      formatter: (val) => Math.floor(val),
    },
  },
  plotOptions: {
    bar: {
      borderRadius: 8,
      columnWidth: '50%',
      distributed: false,
    },
  },
  dataLabels: {
    enabled: false,
  },
  tooltip: {
    theme: 'light',
    y: {
      formatter: (val) => `${val} 个单词`,
    },
  },
  colors: ['#5855D6'],
  fill: {
    type: 'gradient',
    gradient: {
      shade: 'dark',
      type: 'vertical',
      gradientToColors: ['#9d8cf8'],
      shadeIntensity: 0.3,
      opacityFrom: 0.7,
      opacityTo: 0.25,
      stops: [0, 100],
    },
  },
  grid: {
    borderColor: '#ddd',
  },
});

const series5Months = computed(() => [
  {
    name: '月度背诵单词数',
    data: last5MonthsData.value.map((x) => x.totalWords),
  },
]);

/* ========== 绿点阵图（过去 365 天） ========== */
// 1. 计算过去365天的数据
const last365DaysData = computed(() => {
  const today = new Date();
  // 向前 364 天 + 今天 = 365 天
  const daysAgo = subDays(today, 364);
  const map = {};

  dailyActivities.value.forEach((item) => {
    const d = parseISO(item.date);
    if (d >= daysAgo && d <= today) {
      map[item.date] = (map[item.date] || 0) + item.words_learned;
    }
  });

  const result = [];
  for (let i = 0; i < 365; i++) {
    const dStr = format(subDays(today, 364 - i), 'yyyy-MM-dd');
    result.push({
      date: dStr,
      words_learned: map[dStr] || 0,
    });
  }
  return result;
});

// 2. 将365天数据拆成按周排列(约53周)，每周7天
const heatmapSeries = computed(() => {
  const chunkSize = 56; // 这里可自行微调
  const arr = [];
  const allData = last365DaysData.value;

  // 最多会有 53 周 (53*7=371)
  for (let w = 0; w < 53; w++) {
    const sliceData = allData.slice(w * chunkSize, w * chunkSize + chunkSize);
    if (!sliceData.length) break;
    arr.push({
      name: `Week ${w + 1}`,
      data: sliceData.map((item) => ({
        x: item.date.slice(5), // 只显示 月-日
        y: item.words_learned,
      })),
    });
  }
  return arr;
});

// 3. Heatmap 图表配置：让格子更窄 & 覆盖一年
const heatmapOptions = reactive({
  chart: {
    type: 'heatmap',
    toolbar: { show: false },
    background: 'transparent',
    fontFamily: 'inherit',
  },
  plotOptions: {
    heatmap: {
      enableShades: false,
      radius: 2,
      colorScale: {
        inverse: false,
        min: 0,
        max: 10,
        ranges: [
          {
            from: 0,
            to: 0,
            name: '0个',
            color: '#d4d4d4',
          },
          {
            from: 1,
            to: 20,
            name: '1-20个',
            color: '#a7f3d0',
          },
          {
            from: 21,
            to: 50,
            name: '20 - 50个',
            color: '#6ee7b7',
          },
          {
            from: 50,
            to: 999999,
            name: '50+个',
            color: '#34d399',
          },
        ],
      },
    },
  },
  tooltip: {
    enabled: true,
    shared: false,
    intersect: true,
    custom: function({ series, seriesIndex, dataPointIndex, w }) {
      const cellData = w.config.series[seriesIndex].data[dataPointIndex];
      const dateStr = cellData.x;
      const words = cellData.y;
      return `
          <div class="custom-heatmap-tooltip p-2 rounded" 
              style="background: #fff; box-shadow: 0 2px 6px rgba(0,0,0,0.15);">
            <div><strong>日期</strong>: ${dateStr}</div>
            <div><strong>背诵</strong>: ${words} 个</div>
          </div>
        `;
    },
  },
  // 隐藏坐标轴 & 网格
  xaxis: {
    show: false,
    labels: { show: false },
    axisBorder: { show: false },
    axisTicks: { show: false },
    tooltip: { enabled: false },
  },
  yaxis: {
    show: false,
    labels: { show: false },
    axisBorder: { show: false },
    axisTicks: { show: false },
  },
  grid: {
    show: false,
    padding: {
      top: 0, right: 0, bottom: 0, left: 0,
    },
  },
  legend: {
    show: false,
  },
  dataLabels: {
    enabled: false,
  },
});

/* ========== 编辑用户信息 (用户名 & 头像) ========== */
const editUsername = ref(user.value?.username || '');
const selectedAvatarFile = ref(null);
const previewAvatar = ref(null);
const updateProfileLoading = ref(false);

// 打开模态框
function toggleEditUserModal() {
  editUsername.value = user.value?.username || '';
  selectedAvatarFile.value = null;
  previewAvatar.value = null;
  const modalEl = document.getElementById('editUserModal');
  if (!modalEl) return;
  const modalObj = new bootstrap.Modal(modalEl);
  modalObj.show();
}

function onAvatarSelected(e) {
  const file = e.target.files?.[0];
  if (file) {
    selectedAvatarFile.value = file;
    const reader = new FileReader();
    reader.onload = (evt) => {
      previewAvatar.value = evt.target?.result;
    };
    reader.readAsDataURL(file);
  }
}

// 更新个人信息
async function updateProfile() {
  if (!editUsername.value) {
    alert('用户名不能为空');
    return;
  }
  updateProfileLoading.value = true;
  try {
    // 假设有后端接口 /api/user/updateProfile/
    // const formData = new FormData();
    // formData.append('username', editUsername.value);
    // if (selectedAvatarFile.value) {
    //   formData.append('avatar', selectedAvatarFile.value);
    // }
    // await store.dispatch('updateUserProfile', formData);

    // 演示用setTimeout模拟
    await new Promise((resolve) => setTimeout(resolve, 800));

    // 更新完毕后, 刷新用户信息
    await store.dispatch('refreshUser');
    alert('修改成功');

    // 关闭模态框
    const modalEl = document.getElementById('editUserModal');
    const modalObj = bootstrap.Modal.getInstance(modalEl);
    modalObj?.hide();
  } catch (err) {
    console.error('更新用户信息失败', err);
    alert(err.detail || '更新失败');
  } finally {
    updateProfileLoading.value = false;
  }
}
</script>

<style scoped>
/* ======= 基础排版与占位 ======= */
.user-profile-page {
  position: relative;
  min-height: 100vh;
  overflow-x: hidden;
  overflow-y: auto;
  margin-top: 80px; /* 预留导航栏高度，可根据实际情况调整 */
}

/* ======= 背景与沉浸式风格 ======= */
.immersive-background {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(130deg, #b2f7ef 0%, #5fbff9 100%);
  z-index: -3;
  transition: all 0.8s ease-in-out;
}
.immersive-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: radial-gradient(
    circle at 50% 50%,
    rgba(255, 255, 255, 0.15) 0%,
    rgba(255, 255, 255, 0.05) 60%,
    transparent 100%
  );
  z-index: -2;
  pointer-events: none;
}

/* ======= 浮动装饰形状 ======= */
.floating-shapes-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
}
.floating-shape {
  position: absolute;
  width: 60px;
  height: 60px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  animation: float-shape 5s ease-in-out infinite;
}
.floating-shape:nth-child(1) {
  top: 10%;
  left: 20%;
  animation-delay: 0s;
}
.floating-shape:nth-child(2) {
  top: 30%;
  left: 70%;
  animation-delay: 2s;
}
.floating-shape:nth-child(3) {
  top: 60%;
  left: 40%;
  animation-delay: 4s;
}
.floating-shape:nth-child(4) {
  top: 80%;
  left: 80%;
  animation-delay: 1s;
}
.floating-shape:nth-child(5) {
  top: 50%;
  left: 10%;
  animation-delay: 3s;
}
.floating-shape:nth-child(6) {
  top: 20%;
  left: 50%;
  animation-delay: 2.5s;
}
.floating-shape:nth-child(7) {
  top: 70%;
  left: 25%;
  animation-delay: 4.5s;
}
.floating-shape:nth-child(8) {
  top: 10%;
  left: 80%;
  animation-delay: 3.5s;
}

@keyframes float-shape {
  0% {
    transform: translateY(0) scale(1);
  }
  50% {
    transform: translateY(-30px) scale(1.2);
  }
  100% {
    transform: translateY(0) scale(1);
  }
}

/* ======= 页面内容卡片样式 ======= */
.user-profile-container {
  z-index: 1;
}
.user-info-card {
  background-color: rgba(255, 255, 255, 0.9);
  border-radius: 12px;
  backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.user-info-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}

/* ======= 头像与小动画 ======= */
.avatar {
  position: relative;
}
.float-decoration {
  position: absolute;
  bottom: -6px;
  right: -6px;
  width: 16px;
  height: 16px;
  background: #90f5da;
  border-radius: 50%;
  animation: floatAnim 3s ease-in-out infinite;
  opacity: 0.8;
}
@keyframes floatAnim {
  0% {
    transform: translateY(0) scale(1);
  }
  50% {
    transform: translateY(-8px) scale(1.2);
  }
  100% {
    transform: translateY(0) scale(1);
  }
}
.img-shadow {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

/* ======= 模态框 ======= */
.modal-content {
  background-color: #fff;
  color: #000;
  border-radius: 12px;
}
.btn-close {
  filter: none;
}
</style>
